package com.example.validation.exception;

import jakarta.annotation.Resource;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 全局异常处理器
 * 统一处理常见异常，返回标准化错误响应
 */
@RestControllerAdvice
public class GlobalExceptionHandler {

    @Resource
    private MessageSource messageSource;

    /**
     * 处理 @Valid 校验失败异常（JSON 请求体校验）
     * 适用于 @RequestBody + @Valid 的场景
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<String> handleValidationException(
            MethodArgumentNotValidException ex,
            Locale locale) {
        String errorMsg = ex.getBindingResult().getAllErrors().stream()
                .map(error -> messageSource.getMessage(error, locale))
                .collect(Collectors.joining(", "));
        return ResponseEntity.badRequest().body(errorMsg);
    }

    /**
     * 处理 @Valid 校验失败异常（JSON 请求体校验）
     * 适用于 @RequestBody + @Valid 的场景
     */
//    @ExceptionHandler(MethodArgumentNotValidException.class)
//    public ResponseEntity<ErrorResponse> handleMethodArgumentNotValid(
//            MethodArgumentNotValidException ex) {
//        Locale locale = LocaleContextHolder.getLocale(); // 获取当前语言环境
//        List<String> errors = new ArrayList<>();
//
//        // 遍历所有字段错误，获取国际化消息
//        for (FieldError fieldError : ex.getBindingResult().getFieldErrors()) {
//            String message = messageSource.getMessage(fieldError, locale);
//            errors.add(fieldError.getField() + ": " + message);
//        }
//
//        ErrorResponse errorResponse = new ErrorResponse(
//                HttpStatus.BAD_REQUEST.value(),
//                "参数校验失败",
//                errors,
//                new Date()
//        );
//
//        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorResponse);
//    }

    /**
     * 处理表单提交或普通参数校验异常（如 @Valid on @ModelAttribute）
     */
    @ExceptionHandler(BindException.class)
    public ResponseEntity<ErrorResponse> handleBindException(BindException ex) {
        Locale locale = LocaleContextHolder.getLocale();
        List<String> errors = new ArrayList<>();
        for (FieldError fieldError : ex.getFieldErrors()) {
            String msg = messageSource.getMessage(fieldError, locale);
            errors.add(fieldError.getField() + ": " + msg);
        }

        ErrorResponse response = new ErrorResponse(
                HttpStatus.BAD_REQUEST.value(),
                "数据绑定失败",
                errors,
                new Date()
        );
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response);
    }

    /**
     * 处理方法参数校验异常（如方法参数上使用 @NotBlank 等）
     * 常见于 @RequestParam + @Validated 的组合
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public ResponseEntity<ErrorResponse> handleConstraintViolation(
            ConstraintViolationException ex) {
        Locale locale = LocaleContextHolder.getLocale();
        List<String> errors = new ArrayList<>();
        for (ConstraintViolation<?> violation : ex.getConstraintViolations()) {
            String message = messageSource.getMessage(
                    violation.getMessageTemplate(),
                    new String[]{violation.getMessage()},
                    locale);
            errors.add(violation.getPropertyPath() + ": " + message);
        }

        ErrorResponse response = new ErrorResponse(
                HttpStatus.BAD_REQUEST.value(),
                "参数约束违反",
                errors,
                new Date()
        );
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response);
    }

    /**
     * 处理参数类型不匹配异常（如期望 Long，传了 String）
     */
    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public ResponseEntity<ErrorResponse> handleTypeMismatch(
            MethodArgumentTypeMismatchException ex) {
        String error = String.format(
                "参数 '%s' 类型错误，期望类型为 %s，实际传入 '%s'",
                ex.getName(),
                ex.getRequiredType().getSimpleName(),
                ex.getValue()
        );

        ErrorResponse response = new ErrorResponse(
                HttpStatus.BAD_REQUEST.value(),
                "参数类型不匹配",
                Collections.singletonList(error),
                new Date()
        );
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response);
    }

    /**
     * 处理缺少必要请求参数异常（如缺少 ?name=xxx）
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public ResponseEntity<ErrorResponse> handleMissingParam(
            MissingServletRequestParameterException ex) {
        String error = String.format(
                "缺少必要参数 '%s'，类型为 '%s'",
                ex.getParameterName(),
                ex.getParameterType()
        );

        ErrorResponse response = new ErrorResponse(
                HttpStatus.BAD_REQUEST.value(),
                "缺少请求参数",
                Collections.singletonList(error),
                new Date()
        );
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response);
    }

    /**
     * 处理 HTTP 请求方法不支持（如用 GET 访问只支持 POST 的接口）
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public ResponseEntity<ErrorResponse> handleMethodNotSupported(
            HttpRequestMethodNotSupportedException ex) {
        String supported = Arrays.toString(ex.getSupportedMethods());
        String error = String.format("请求方法 '%s' 不被支持，支持的方法有: %s", ex.getMethod(), supported);

        ErrorResponse response = new ErrorResponse(
                HttpStatus.METHOD_NOT_ALLOWED.value(),
                "方法不被允许",
                Collections.singletonList(error),
                new Date()
        );
        return ResponseEntity.status(HttpStatus.METHOD_NOT_ALLOWED).body(response);
    }

    /**
     * 处理不支持的媒体类型（如 Content-Type: text/plain）
     */
    @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
    public ResponseEntity<ErrorResponse> handleMediaTypeNotSupported(
            HttpMediaTypeNotSupportedException ex) {
        String error = String.format(
                "不支持的媒体类型 '%s'，支持的类型有: %s",
                ex.getContentType(),
                ex.getSupportedMediaTypes()
        );

        ErrorResponse response = new ErrorResponse(
                HttpStatus.UNSUPPORTED_MEDIA_TYPE.value(),
                "不支持的媒体类型",
                Collections.singletonList(error),
                new Date()
        );
        return ResponseEntity.status(HttpStatus.UNSUPPORTED_MEDIA_TYPE).body(response);
    }

    /**
     * 兜底异常处理器：捕获所有未处理的异常
     * 防止系统内部错误直接暴露给前端
     */
    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleGeneralException(Exception ex) {
        // 生产环境建议记录日志，不暴露堆栈
        // logger.error("服务器内部错误", ex);

        ErrorResponse response = new ErrorResponse(
                HttpStatus.INTERNAL_SERVER_ERROR.value(),
                "服务器内部错误，请稍后重试",
                Collections.singletonList("请联系管理员或查看日志"),
                new Date()
        );
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
    }
}
